#include "syscall.h"
#include <malloc.h>
#include "filesys.h"
#include "sysdep.h"
#include "openfile.h"
#include "thread.h"
#include "userkernel.h"
#include "alarm.h"

Syscall::Syscall() : inputRedirected(0), outputRedirected(1) 
{
}
list<ListaProc> *l =  new list<ListaProc>;
list<ListaProc>::iterator i;
OpenFile *o[30]; 
Alarm *a;
int nr_fis=0;
int nr_proc=0;

void insert(Thread* th, int id)
{
    //parcurgem lista si vedem daca exista deja procesul
    int ok=0;
    if(l!=NULL)
        for(i = l->begin(); i!=l->end();i++){
         //   if(!strcmp(i->proces->name,th->name)){
              if(i->proces == th){
                //daca procesul exista deja atunci mai adaug doar fisierul
                i->id_fisiere.push_back(id);
                ok =1;
                break;
            }    
        }
    if(!ok){
        //daca procesul nu exista in lista adaug si procesul si fisierul nou
        //deschis
        ListaProc *test = new ListaProc;
        test->proces = th;
        test->proces->SetJoinable(true);
        test->id_fisiere.push_back(id);
        l->push_back(*test); 
        nr_proc++;
    }
}

void addThread(Thread *th)
{
     ListaProc *test = new ListaProc;
     test->proces = th;
     test->proces->SetJoinable(true);
     l->push_back(*test); 
     
     nr_proc++;
     
}

Thread* findThread(char* name,int id) {
    if ( name == NULL ) {
        if(id==0) return NULL;
        else{
                int contor=1;
                cout<<contor<<endl;
            	for ( i = l->begin() ; i != l->end(); i++ ) {
                if(contor==id) return i->proces;
                contor++;
                }
        }
	}
	else {
		for ( i = l->begin() ; i != l->end(); i++ ) {
			if ( strcmp(i->proces->getName(), name ) == 0 ) {
				return i->proces;
			}
		}
	}
	return NULL;
}

void remove(Thread* th, int id)
{
    if(l!=NULL)
    for(i = l->begin(); i!=l->end();i++){
      //  if(!strcmp(i->proces->name,th)){
          if(i->proces == th){
            //facem close la fisier si apoi il stergem din lista
            delete o[id]; //eliberam obiectul - echivalient cu inchiderea fisierului
            i->id_fisiere.remove(id);
            break;
        }
    }
}

void removeall(Thread* th)
{
    list<int>::iterator i2;
    if(l!=NULL)
    for(i = l->begin(); i!=l->end();i++){
     //   if(!strcmp(i->nume_proces,nume)){
        if(i->proces == th){
            //parcurgem lista si facem close la fisiere si apoi le stergem din lista
            for(i2 = i->id_fisiere.begin(); i2!=i->id_fisiere.end();i2++)
                  delete o[*i2];                 
            break;
        }
    }
}


void Syscall::Halt(){
    return ;
}

void Syscall::Exit(int status)
{

    removeall(kernel->currentThread); 

    return ;
}

SpaceId Syscall::Exec(Thread *th)
{
    addThread(th);
    return nr_proc;
}

int Syscall::Join(SpaceId id)
{
    kernel->currentThread->Join(findThread(NULL,id));
    return 0;

}

void Syscall::WaitUntil(int time) {

   if ( time >= 0 ) {
	DEBUG(dbgMe,"WAIT UNTIL ");
	a = new Alarm(false);
	a->WaitUntil(time);
   }
}

int Syscall::getNoOfSleepingThreads() {
	DEBUG(dbgMe, "Get No Of Sleeping Threads");
	
	return a->nr1;
}

void Syscall::Create(char* name)
{
    //crearea unui fisier nu am considerat-o si deschiderea lui deci nu adaugam
    //nimic in lista de procese si fisiere, apelam doar Create
   if ( name != NULL ) {    
	   kernel->fileSystem->Create(name);       
    }
    else {
    	return;
    }
}

OpenFileId Syscall::Open(char *name)
{
	if (name != NULL)
	{
		int fd;
    	o[nr_fis] = kernel->fileSystem->Open(name);
        if(o[nr_fis] != NULL)
        {
        	insert(kernel->currentThread, nr_fis);
        	//  o->Write("www",2);
        	nr_fis++;
        	return (nr_fis+1);
        }
        else 
            return -1;
    }
    else
    	return -1;
  
}

/*void Syscall::Write(OpenFileId id, char *buffer, int size)
{
	if(id == 1){
	       	cout << buffer;
	}
    else
        o[id-2]->Write(buffer, size); 
	return;
}


int Syscall::Read(OpenFileId id,char *buffer, int size)
{
    if(id == 0){
        //cin >> buffer;
	char *b = buffer;
	while(size) {
		*b = getchar();
		b++;
		size--;
	}
    }
    else
        o[id-2]->Read(buffer, size);
    return 0;

}*/

void Syscall::Close(OpenFileId id)
{
    //steregem fisierul din lista de fisiere deschise si eliberam obiectul
    //OpenFile corespunzator

    remove(kernel->currentThread, id - 2);
    printf("Close ok \n");
}

void Syscall::RedirectDescriptor(OpenFileId id, const char* name)
{
	if(id == 0)
	{
		inputRedirected = Open(const_cast<char*>(name));	
	}
	else if(id == 1)
	{
		outputRedirected = Open(const_cast<char*>(name));
	}
}

void Syscall::Write(OpenFileId id, char *buffer, int size)
{
	if(id == 1 && outputRedirected == 1)
       	cout << buffer;
    else
        o[id-2]->Write(buffer, size); 
	return;
}

int Syscall::Read(OpenFileId id,char *buffer, int size)
{
    if(id == 0 && inputRedirected == 0)
    {
		char *b = buffer;
		while(size) {
			*b = getchar();
			b++;
			size--;
		}
	}
    else
        o[id-2]->Read(buffer, size);
    return 0;

}
